Skip to content

feat(showcase): actually exercise the per-group (会签) approval demo#3409

Merged
os-zhuang merged 1 commit into
mainfrom
feat/showcase-per-group-signoff
Jul 22, 2026
Merged

feat(showcase): actually exercise the per-group (会签) approval demo#3409
os-zhuang merged 1 commit into
mainfrom
feat/showcase-per-group-signoff

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

The gap

showcase_expense_signoff is the only flow in the showcase authoring behavior: 'per_group' — but no request was ever opened against it, so #3358 §1 "Per-group sign-off (会签) — configure per_group with 2 named groups; confirm it needs one approval from each group" had nothing to look at. Two independent reasons:

  1. The approval demo seed launched only the unanimous invoice flow and the quorum committee flow.
  2. Nobody held auditor — the position behind the flow's finance group — so even if it had fired, that group would have resolved to an empty slate.

The fix

  • Ada Auditor (demo) persona holding only auditor. It must be a different user from the admin: with one user in both groups a single decision satisfies both tallies at once, and "one approval per group" is never observable.
  • Launch showcase_expense_signoff on EXP-2001 ($1,500) — deliberately under the $5,000 committee threshold, so the quorum flow doesn't also open a request on the same record and blur the two demos.
  • Housekeeping: generalise ensurePhoneDemoUserensureDemoUser (returns the id) and assignAdminPositionsassignPositions; fix a comment that labelled the unanimous invoice flow as 会签.

Verified

On a wiped dev DB the request opens with the slate resolved across both groups, not collapsed onto one user:

process_name      = flow:showcase_expense_signoff
behavior          = per_group,  minApprovals = 1
approvers         = [ {position: manager, group: manager},
                      {position: auditor, group: finance} ]
pending_approvers = <admin>, usr_showcase_auditor_demo
status            = pending

Boot log stays at 0 ERROR; the other two demos are untouched — 3 pending requests now, one per behavior (unanimous / quorum / per_group). tsc --noEmit

Stacked on #3408. From the #3358 §1 evidence pass. Private example → no changeset.

🤖 Generated with Claude Code

`showcase_expense_signoff` is the only flow authoring `behavior: 'per_group'`
(manager group ← position `manager`, finance group ← position `auditor`), but
nothing ever opened a request against it, so #3358 §1 "Per-group sign-off (会签)"
had nothing to look at:

  * the approval demo seed launched only the `unanimous` invoice flow and the
    `quorum` committee flow; and
  * nobody held `auditor`, so even if it had fired, the finance group would
    have resolved to an empty slate.

Give the finance group a real holder and launch the flow:

  * add an `Ada Auditor (demo)` persona holding ONLY `auditor`. It has to be a
    *different* user from the admin — with one user in both groups a single
    decision satisfies both tallies at once and "one approval per group" is
    never observable.
  * launch `showcase_expense_signoff` on EXP-2001 ($1,500), deliberately UNDER
    the $5,000 committee threshold so the quorum flow does not also open a
    request on the same record and blur the two demos.

Generalises the two single-purpose helpers (`ensurePhoneDemoUser` →
`ensureDemoUser` returning the id; `assignAdminPositions` → `assignPositions`)
and corrects a comment that labelled the `unanimous` invoice flow as 会签.

Verified on a wiped dev DB — the request opens with the slate resolved across
both groups, not collapsed onto one user:

    process_name    = flow:showcase_expense_signoff
    behavior        = per_group,  minApprovals = 1
    approvers       = [position manager @group manager,
                       position auditor @group finance]
    pending_approvers = <admin>, usr_showcase_auditor_demo
    status          = pending

Boot log stays at 0 ERROR; the other two demos are unchanged (3 pending
requests now: unanimous, quorum, per_group). `tsc --noEmit` passes.

From the #3358 §1 evidence pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 22, 2026 2:23pm

Request Review

@os-zhuang os-zhuang added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Jul 22, 2026
@os-zhuang
os-zhuang merged commit b132181 into main Jul 22, 2026
19 of 21 checks passed
@os-zhuang
os-zhuang deleted the feat/showcase-per-group-signoff branch July 22, 2026 14:28
os-zhuang added a commit that referenced this pull request Jul 22, 2026
…#3411)

Every seeded request had a null submitter, because the demo launches flows as
SYS and the approval node stamps the requester from the flow context
(`submitterId: context?.userId ?? null`, approval-node.ts). Consequences, all
invisible until you go looking:

  * 申请人 rendered as `—` on every row and in the drawer;
  * the "我发起的" inbox tab was empty for every user, so that whole surface
    was dead; and
  * the submitter-only affordances never rendered anywhere — `Send reminder`
    and `Recall` are gated on `submitter_id == ctx.user.id`, so with no
    submitter they were unreachable and only 5 of the 7 declared approval
    actions could ever appear.

Pass `userId` on the engine context and route it deliberately:

  * Invoice Dual Sign-off → submitted by the **admin**, so the logged-in dev
    admin owns one request and "我发起的" is non-empty with the submitter-only
    actions visible;
  * Committee Quorum and Expense Sign-off → submitted by **Mei Phone (demo)**,
    who holds no approval position and is therefore a clean requester who is
    never one of her own approvers.

Verified in the running console: 申请人 now shows real names, "我发起的" holds
the admin's request, and the same viewer sees `Approve / Reject / Reassign /
Send back / Request info` on Mei's requests but those **plus** `Send reminder`
and `Recall` on his own — i.e. all 7 declared actions render, gated by role.
`tsc --noEmit` passes; boot log stays at 0 ERROR.

From the #3358 §1 evidence pass; follow-up to #3409.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant